package com.guiji.testcase;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.guiji.constant.Constant;
import com.guiji.entity.*;
import com.guiji.utils.*;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;

import java.lang.reflect.InvocationTargetException;
import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @description:
 * @author: Jodie
 * @time: 2022/11/15
 */
@Slf4j
public class ClientTest {

    @SneakyThrows
    public static void main(String[] args) {
        long s = System.currentTimeMillis();
        List<TestCase> testCases = ExcelUtils.readAllData(Constant.TEST_CASE_PATH, 1, TestCase.class);
        testCases = testCases.stream().filter(t -> t.getRun().equalsIgnoreCase("Y")).collect(Collectors.toList());
        List<String> sheetNames = ExcelUtils.getAllSheetName(Constant.TEST_CASE_PATH);
        List<CaseParams> caseParams = new ArrayList<>();
        List<TestResult> testResults = new ArrayList<>();
        Map<String, TestStatistics> statisticsMap = new HashMap<>();
        for (TestCase testCase : testCases) {
            String sheetName = testCase.getParams().split("-")[1];

            for (int i = 0; i < sheetNames.size(); i++) {
                if (sheetNames.get(i).equals(sheetName)) {
                    caseParams = ExcelUtils.readAllData(Constant.TEST_CASE_PATH, i + 2, CaseParams.class);
                    break;
                }
            }

            if (!statisticsMap.containsKey(testCase.getModule())) {
                statisticsMap.put(testCase.getModule(), new TestStatistics());
            }
            TestStatistics testStatistics = statisticsMap.get(testCase.getModule());
            testStatistics.setModule(testCase.getModule());
            List<TestResult> resultList = runCase(caseParams, testCase, testStatistics);
            testResults.addAll(resultList);
        }

        for (TestStatistics statistics : statisticsMap.values()) {
            statistics.setStatistics(getStatisticsFormat(statistics));
            List<String> errorList = statistics.getRetry().stream().map(TestCase::getUrl).distinct().collect(Collectors.toList());
            statistics.setErrorApis(errorList.toString());
            for (TestCase testCase : statistics.getRetry()) {
                System.out.println("testCase = " + testCase);
            }
        }


        String resultPath = Constant.BASE_PATH + "/result/" + DateUtils.getCurrentDateTime() + ".xlsx";
        ExcelWriter excelWriter = EasyExcel.write(resultPath).build();
        writeSheetToExcel(excelWriter, "测试结果", testResults, TestResult.class);
        writeSheetToExcel(excelWriter, "统计", statisticsMap.values(), TestStatistics.class);

        excelWriter.finish();

        long e = System.currentTimeMillis();
        System.out.println("spend time:" + (e - s));
    }

    private static int retryCount = 0; //已经重试次数

    private static final int retryMax = PropertiesUtils.getInt("retry.max");

    private static final boolean retrySleep = PropertiesUtils.getBoolean("retry.sleep");

    private static final int sleepTime = PropertiesUtils.getInt("retry.sleepTime");

    private static void retry(List<TestResult> testResults, ExcelWriter excelWriter) {
        log.info("调用次数------{}", retryCount);
        if (retryCount++ >= retryMax) {
            return;
        }

        //控制重试频率
        if (retrySleep) {
            try {
                TimeUnit.SECONDS.sleep((long) sleepTime * retryCount);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        List<TestResult> failList = testResults.stream().filter(t -> t.getCheckpointResult().equalsIgnoreCase("Fail")).collect(Collectors.toList());
        if (!failList.isEmpty()){
            for (TestResult testResult : failList) {
                HttpResult httpResult = HttpUtils.sendRequest(testResult);
            }
        }
        // todo

    }

    public static List<TestResult> runCase(List<CaseParams> caseParams, TestCase testCase, TestStatistics testStatistics) {
        List<TestResult> testResults = new ArrayList<>();
        if (!caseParams.isEmpty()) {
            caseParams.forEach(caseParam -> {
                if (caseParam.getBusiness().equalsIgnoreCase(testCase.getBusiness())) {
                    testCase.setParams(ParamUtils.regexReplace(caseParam.getParam()));
                    if (!testCase.isAlreadyReplace()) {
                        ParamUtils.paramsReplace(testCase);
                        testCase.setAlreadyReplace(true);
                    }
                    HttpResult httpResult = HttpUtils.sendRequest(testCase);
                    ParamUtils.extractValueFromRes(httpResult, caseParam);
                    caseParam.setExpectedResult(ParamUtils.regexReplace(caseParam.getExpectedResult()));
                    boolean assertResult = ParamUtils.assertResponse(caseParam, httpResult);
                    TestResult testResult = new TestResult();
                    try {
                        BeanUtils.copyProperties(testResult, caseParam);
                        testResult.setHttpResult(httpResult.getMsg());
                        BeanUtils.copyProperties(testResult, testCase);
                        testResults.add(testResult);
                        if (assertResult) {
                            testStatistics.setSuccess(testStatistics.getSuccess() + 1);
                            testResult.setCheckpointResult("Success");
                        } else {
                            testStatistics.setError(testStatistics.getError() + 1);
                            testStatistics.getRetry().add(testCase);
                            testResult.setCheckpointResult("Fail");
                        }

                    } catch (IllegalAccessException | InvocationTargetException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
        return testResults;
    }

    public static String getStatisticsFormat(TestStatistics testStatistics) {
        DecimalFormat df = new DecimalFormat("0.0");
        int success = testStatistics.getSuccess();
        int all = testStatistics.getSuccess() + testStatistics.getError();
        String format = df.format(((double) success / all) * 100);
        return format + "%";
    }

    public static void writeSheetToExcel(ExcelWriter writer, String sheetName, Collection<?> data, Class<?> clazz) {
        WriteSheet sheet = EasyExcel.writerSheet(sheetName).head(clazz).build();
        writer.write(data, sheet);
    }
}

